/*******************************************************************
 *
 * Copyright (C), 2021-2022, LS, All rights reserved.
 *
 * Author      : 
 * Create Time : 2021-09-17
 * Version     : v0.1
 * Description : 
 *******************************************************************/
 
/*----------------------------Head file----------------------------*/
#include "ls_ble_crc16.h"
#include "ls_ble_adpter.h"
#include "ls_ble_ota_flash.h"
#include "ls_ble_sdk_config.h"
#include "ls_ble_ota_protocol.h"
#include "user_config.h"

#define OTA_SF_LOG_ENABLE      1

#if OTA_SF_LOG_ENABLE
#include "ls_ble_log.h"
#define TAG                     "ota_flash"
#define OTA_SF_LOG(level, ...)  LS_BLE_LOG_PRINT(level, TAG, ##__VA_ARGS__)
#else
#define OTA_SF_LOG(...)
#endif

/*----------------------------macro file---------------------------*/
#define LS_BLE_FLASH_SECTOR_SIZE    0x1000

#define ota_flash_erase_sector(addr)    ls_ble_adpter_flash_erase_sector(addr)
#define ota_flash_write				    ls_ble_adpter_flash_write
#define ota_flash_read                  ls_ble_adpter_flash_read

#define ota_wdt_feed                    ls_ble_adpter_wdt_feed

/*----------------------------type define--------------------------*/

/*----------------------------var define---------------------------*/							
OtaFlashCtl_t otaFlashCtl;

/*-------------------------func declaration------------------------*/

/*-----------------------------------------------------------------*/

void ota_flash_image_acitve(void)
{
    uint8_t data[4] = {0x4f, 0x54, 0x41, 0x46}; //tag string = "OTAF"
    ota_flash_write(OTA_IMG_START_ADDR, data, sizeof(data));
}

bool ota_flash_check_header(uint32_t image_size)
{
    BankBootInfoHeader_t info;
    
    ota_flash_read(OTA_IMG_START_ADDR, (uint8_t*)&info, sizeof(info));
	
	if(info.partition_num < 2 || info.partition_num > OTAF_PARTITION_NUM_MAX) {
        OTA_SF_LOG(LOG_LVL_ERROR, "partition_num err: %d.", info.partition_num);
		return false;
	}
	
    if( (info.part_info[1] & 0xffff0000) != 0xffff0000) {
        OTA_SF_LOG(LOG_LVL_ERROR, "part info err: %x.", info.part_info[1]);
        return false;
    }
    
    if(image_size > APP_IMG_MAX_SIZE) {
        OTA_SF_LOG(LOG_LVL_ERROR, "image_size err: %d.", image_size);
        return false;
    }

	return true;
}


void ota_flash_write_data(uint8_t *buf, uint32_t len)
{
	uint32_t offset;
	uint32_t wrLen;
	uint8_t *ptr;

	ptr = buf;
	offset = OTA_IMG_START_ADDR + otaFlashCtl.write_size;
	
	if((offset + len) >= OTA_IMG_END_ADDR) {
		OTA_SF_LOG(LOG_LVL_ERROR, "ota write out of size\n");
		return;
	}
	
	if(((offset+len-1)&0xFFFFFF00) != (offset&0xFFFFFF00)) {
		wrLen = 0x100 - (offset&0xFF);
		/*if((offset % LS_BLE_FLASH_SECTOR_SIZE) == 0) {
			ota_flash_erase_sector(offset);
		}*/
		ota_flash_write(offset, ptr, wrLen);
		offset += wrLen;
		ptr += wrLen;
		wrLen = len-wrLen;
	}
	else {
		wrLen = len;
	}
	/*if((offset % LS_BLE_FLASH_SECTOR_SIZE) == 0) {
		ota_flash_erase_sector(offset);
	}*/
	ota_flash_write(offset, ptr, wrLen);
	otaFlashCtl.write_size += len;
}


void ota_flash_buf_conti_write_data(uint8_t *buf, uint32_t len, uint32_t bin_size)
{
    uint32_t wr_offset = OTA_IMG_START_ADDR + otaFlashCtl.write_size;

    if(wr_offset < OTA_IMG_START_ADDR || wr_offset >= OTA_IMG_END_ADDR) {
        OTA_SF_LOG(LOG_LVL_ERROR, "ota write out of size");
    }

    if((otaFlashCtl.write_idx + len) < OTA_FLASH_BUF_MAX_SIZE) {
        memcpy(&otaFlashCtl.flash_buf[otaFlashCtl.write_idx], buf, len);
        otaFlashCtl.write_idx += len;
    }
    else {
        uint8_t rest_len = OTA_FLASH_BUF_MAX_SIZE - otaFlashCtl.write_idx;
        memcpy(&otaFlashCtl.flash_buf[otaFlashCtl.write_idx], buf, rest_len);
        ota_flash_write(wr_offset, otaFlashCtl.flash_buf, OTA_FLASH_BUF_MAX_SIZE);
        otaFlashCtl.write_size += OTA_FLASH_BUF_MAX_SIZE;
        memcpy(otaFlashCtl.flash_buf, &buf[rest_len], len - rest_len);
        otaFlashCtl.write_idx = len - rest_len;
    }
    if((otaFlashCtl.write_size + otaFlashCtl.write_idx) >= bin_size) {
        wr_offset = OTA_IMG_START_ADDR + otaFlashCtl.write_size;
        LS_BLE_LOG_RAW_INFO("Trans done.\n");
        ota_flash_write(wr_offset, otaFlashCtl.flash_buf, otaFlashCtl.write_idx);
        otaFlashCtl.write_size += otaFlashCtl.write_idx;
        otaFlashCtl.write_idx = 0;
    }
}


bool ota_flash_calculate_checksum(uint32_t img_cs, uint32_t img_size)
{
	uint32_t i, len;
	uint16_t crc = 0xffff;

	for(i=0;i<img_size;i+=sizeof(otaFlashCtl.flash_buf)) {
		len = img_size - i;
		if(len > sizeof(otaFlashCtl.flash_buf)) {
			len = sizeof(otaFlashCtl.flash_buf);
		}
		ota_flash_read(OTA_IMG_START_ADDR + i, otaFlashCtl.flash_buf, len);
		crc = ls_ble_crc16_calc(otaFlashCtl.flash_buf, len, crc);
	}
	
	OTA_SF_LOG(LOG_LVL_DEBUG, "img_size=%d, CalcCRC=%x, ImgCRC=%x", img_size, crc, img_cs);
	if(crc != img_cs) {
		return false;
	}
	return true;
}


void ota_flash_area_erase(uint32_t bin_size)
{
    if(bin_size <= 0 || bin_size > APP_IMG_MAX_SIZE)    //Prevent device firmware get damaged.
        return;
    
    uint16_t erase_sector_num = (bin_size / LS_BLE_FLASH_SECTOR_SIZE);
    
    if(bin_size < (APP_IMG_MAX_SIZE - LS_BLE_FLASH_SECTOR_SIZE)) {
        erase_sector_num += 1;
    }
    OTA_SF_LOG(LOG_LVL_DEBUG, "erase_sector_num: %d.", erase_sector_num);
    
    for(uint16_t i=0;i<erase_sector_num;i++) {
		ota_flash_erase_sector(OTA_IMG_START_ADDR + i*LS_BLE_FLASH_SECTOR_SIZE);
        ota_wdt_feed();
	}
}

